//
//  NetManager.swift
//  ImGuider X
//
//  Created by llt on 2018/9/13.
//  Copyright © 2018年 imguider. All rights reserved.
//
import Moya

/// 获取验证码
///
/// - register: 注册
/// - retrieve: 重置密码
/// - quicklogin: 快捷登录
enum CodeUsage:Int {
    
    case register
    case retrieve
    case quicklogin
}

/// 网络请求
///
/// - allcountry: 1.01 所有国家列表
/// - encode: 3.01 获取验证码
/// - login: 3.11 手机验证码快捷登录
/// - userinfo: 3.06 获取用户信息
/// - mytrips: 2.01 我的行程列表
/// - bindtrips: 2.09 绑定行程
/// - tripdetail: 2.02 行程的概况

/// - lineinfo: 线路详情
/// - company: 公司简介
/// - forex: 汇率
/// - messages: 公司消息
enum NetAPI {
    
    case allcountry
    case encode(country:String,cellphone:String,useage:CodeUsage)
    case login(country:String,cellphone:String,encode:String)
    case userinfo
    case mytrips
    case bindtrips(tripid:String)
    case tripdetail(tripid:String)
    
    case lineinfo(lineid:String)
    case company(tripid:String)
    case forex
    case messages(tripid:String)
}

extension NetAPI:TargetType {
    
    var baseURL: URL {
        
        return URL(string: kDomain + kSerPath)!
    }
    
    var path: String {
        
        switch self {
            
        case .allcountry:
            
            return "system/allcountry"
            
        case .encode:
            
            return "user/encode"
            
        case .login:
            
            return "user/quicklogin"
        case .userinfo:
            
            return "user/userinfo"
            
        case .mytrips:
            
            return "trip/mytrips"
        case .bindtrips:
            
            return "trip/bindtrips"
            
        case .tripdetail(let tripid):
            
            return "trip/detail/\(tripid)"

        case .lineinfo(let lineid):
            
            return "trip/lineinfo/\(lineid)"
        case .company(let tripid):
            
            return "sys/company/\(tripid)"
            
        case .forex:
            
            return "sys/forex"
        case .messages(let tripid):
            
            return "sys/messages/\(tripid)"
        }
    }
    
    var method: Moya.Method {
        
        switch self {

        case .allcountry, .encode, .login, .bindtrips:
            
            return .post
            
        default:
            
            return .get
        }
    }
    
    var sampleData: Data {
        
        return "{\"status\":0,\"result\":{\"version\":\"2.3.1\"}}".data(using: .utf8)!
    }
    
    var cache:Bool {
        
        switch self {
            
        case .login,.encode,.bindtrips:
            
            return false
        default:
            return true
        }
    }
    
    var params: [String:Any]? {
        
        switch self {
            
        case .encode(let country,let phone,let useage):
            
            return ["countrycode":country,"cellphone":phone,"usage":"\(useage.rawValue)"]
            
        case .login(let country,let phone,let encode):
            
            return ["countrycode":country,"cellphone":phone,"encode":encode]
            
        case .bindtrips(let tripid):
            
            return ["ids":tripid]
        default:
            return nil
        }
    }
    
    var task: Task {
        
        guard let params = params else { return .requestPlain }
        
        return .requestParameters(parameters:params, encoding: JSONEncoding.default)
    }
    
    var headers: [String : String]? {
        
        var headers = ["Content-type":"application/json"]
        
        headers["platform"] = "ios"
        headers["lang"] = AppManager.share.current_language
        headers["currency"] = "CNY"
        
        if let token = UserManager.share.token {
            
            headers["token"] = token
        }
        
        return headers
    }
}

let networkActiovtyPlugin = NetworkActivityPlugin { (change, target) in
    
    DispatchQueue.main.async {
        
        switch(change) {
            
        case .ended:
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
            
        case .began:
            
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
        }
    }
}

let provider = MoyaProvider<NetAPI>(plugins: [NetworkLoggerPlugin(verbose: true),networkActiovtyPlugin])

typealias CompletionBlock = (_ response: Any?,_ errorMsg: String?) -> Void

let dErrmsg = LocalizedString("network_error")

extension NetAPI {
    
    /// 第二次封装，将result中的数据直接返回成指定对象
    ///
    /// - Parameters:
    ///   - type: 返回数据的model类型
    ///   - dealJson: 处理的json e.g.:"blogs" 会在得到的response中取出blogs的一层去处理
    ///   - completion: 完成block
    func request<T: Codable>(_ type:T.Type, dealJson: String? = nil, completion: @escaping CompletionBlock) {
        
        request { (res, err) in
            
            guard let response = res else {
                
                completion(nil,err)
                
                return
            }
            
            var jsonData:Data? = nil
            
            
            if let dealJson = dealJson, let res = response as? [String:Any] {
                
                jsonData = try? JSONSerialization.data( withJSONObject:res[dealJson] ?? res, options:JSONSerialization.WritingOptions.prettyPrinted)
            } else {
                
                jsonData = try? JSONSerialization.data( withJSONObject:response, options:JSONSerialization.WritingOptions.prettyPrinted)
            }
            
            let decoder = JSONDecoder()
            
            decoder.dateDecodingStrategy = .secondsSince1970
            
            guard let jd = jsonData,let model = try? decoder.decode(type.self, from: jd) else {
                
                completion(nil,dErrmsg)
                
                return
            }
            
            completion(model,err)
            
        }
    }
    
    /// 第一部封装网路请求，取出需要的json数据 和 错误信息
    ///
    /// - Parameters:
    ///   - completion: completion: json
    func request(completion:@escaping CompletionBlock) {
        
        provider.request(self) { event in
            
            switch event {
                
            case .success(let response) :
                
                self.dealSuccessJson(response: response, completion: completion)
                return
                
            case .failure(let error):
                
                if self.cache {
                    
                    self.getCache(errmsg: error.localizedDescription, completion: completion)
                    return
                }
                
                completion(nil, error.localizedDescription)
                return
            }
        }
    }
    
    
    /// 处理成功数据
    ///
    /// - Parameters:
    ///   - response: 成功数据
    ///   - completion: --
    private func dealSuccessJson(response:Response,completion:@escaping CompletionBlock) {
        
        guard let mapJson = try? response.mapJSON(), let response = mapJson as? Dictionary<String, Any>  else {
            
            if cache {
                
                self.getCache(errmsg: dErrmsg, completion: completion)
                return
            }
            
            completion(nil,dErrmsg)
            
            return
        }
        
        let code = response["code"] as? Int
            ?? response["status"] as? Int ?? -1
        
        if code == 200 {
            
            guard let result = response["data"] else {
                
                completion(nil,dErrmsg)
                
                return
            }
            
            completion(result, nil)
            
            if !cache {
                
                return
            }
            
            DispatchQueue.global().async {
                
                guard let data = try? JSONSerialization.data(withJSONObject: result, options: JSONSerialization.WritingOptions.prettyPrinted) else {
                    
                    return
                }
                
                CacheManager.share.store(data, forKey: self.cacheKey, toDisk: true)
            }
            
            return
        }
        
        let errmsg:String = response["errmsg"] as? String
            ?? response["message"] as? String ?? dErrmsg
        
        if errmsg.contains("用户令牌过期") {
            
            UserManager.share.token = nil
            
            AppManager.share.loginPage()
            return
        }
        
        if cache {
            
            self.getCache(errmsg: errmsg, completion: completion)
            return
        }
        completion(nil, errmsg)
    }
    
    /// 获取缓存
    ///
    /// - Parameters:
    ///   - errmsg: 错误信息
    ///   - completion: 成功回掉
    private func getCache(errmsg:String?,completion:@escaping CompletionBlock) {
        
        CacheManager.share.retrieve(forKey: self.cacheKey, complete: { data in
            
            if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) {
                
                completion(json, errmsg)
                
                return
            }
            
            completion(nil, errmsg)
        })
    }
}

extension NetAPI {
    
    var cacheKey: String {
        
        let urlStr = baseURL.appendingPathComponent(path).absoluteString
        
        var sortParams = ""
        
        if let params = params {
            /// sort
            let sortArr = params.keys.sorted { (str1, str2) -> Bool in
                return str1 < str2
            }
            
            for str1 in sortArr {
                if let value = params[str1] {
                    sortParams = sortParams.appending("\(str1)=\(value)")
                } else {
                    sortParams = sortParams.appending("\(str1)=")
                }
            }
        }
        
        let key = urlStr.appending("?\(sortParams)")
        
        
        return key.kf.md5
    }
}
